package com.budwk.app.sqfwDoc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.StrFormatter;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import com.budwk.app.exception.Asserts;
import com.budwk.app.exception.ServiceException;
import com.budwk.app.oss.models.SysOss;
import com.budwk.app.oss.services.SysOssService;
import com.budwk.app.sqfwDoc.dto.SqfwTemplateConfigPageQueryDTO;
import com.budwk.app.sqfwDoc.dto.SqfwTemplateDictConfigUpdateDTO;
import com.budwk.app.sqfwDoc.enums.DictEnums;
import com.budwk.app.sqfwDoc.models.SqfwTemplateConfig;
import com.budwk.app.sqfwDoc.models.SqfwTemplateHistory;
import com.budwk.app.sqfwDoc.service.SqfwTemplateDicConfigService;
import com.budwk.app.sqfwDoc.service.SqfwTemplateHistoryService;
import com.budwk.app.sqfwDoc.service.SqfwTemplateVisDictService;
import com.budwk.app.util.poiUtils.CustomImageModifyHandler;
import com.budwk.starter.common.page.Pagination;
import com.budwk.starter.database.service.BaseServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import nl.basjes.shaded.org.springframework.core.io.ClassPathResource;
import org.apache.commons.lang3.StringUtils;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.upload.TempFile;
import org.nutz.trans.Trans;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author ZY.Wang
 * @since 2023/12/5
 */
@IocBean(args = {"refer:dao"})
public class SqfwTemplateDicConfigServiceImpl extends BaseServiceImpl<SqfwTemplateConfig> implements SqfwTemplateDicConfigService {
    public SqfwTemplateDicConfigServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private SqfwTemplateVisDictService sqfwTemplateVisDictService;
    @Inject
    private SqfwTemplateHistoryService sqfwTemplateHistoryService;
    @Inject
    private SysOssService sysOssService;

    @Override
    public Pagination pageListConfig(SqfwTemplateConfigPageQueryDTO config) {

        Cnd cnd = Cnd.NEW();
        if (StringUtils.isNotBlank(config.getConfigName())) {
            cnd.and(SqfwTemplateConfig::getConfigName, "like", StrFormatter.format("%{}%", config.getConfigName()));
        }
        cnd.orderBy(SqfwTemplateConfig::getCreateTime, "desc");
        return listPage(config.getPageNo(), config.getPageSize(), cnd);
    }

    @Override
    public String addDictConfig(String userId, SqfwTemplateDictConfigUpdateDTO data) {
        SqfwTemplateConfig config = new SqfwTemplateConfig();
        Trans.exec(() -> {
            BeanUtil.copyProperties(data, config);
            config.setConfigJson(data.getConfigJson());
            config.setCreateBy(userId);
            config.setCreateTime(new Date());
            config.setUpdateBy(userId);
            config.setUpdateTime(new Date());
            config.setBindingStatus(DictEnums.VIS_DICT_NOT_BINDING.getCode());
            insert(config);

            // 添加历史版本记录
            insertTemplateHistory(userId, data);
        });
        return config.getId();
    }

    @Override
    public void updateDictConfig(String userId, SqfwTemplateDictConfigUpdateDTO data) {
        SqfwTemplateConfig config = new SqfwTemplateConfig();
        BeanUtil.copyProperties(data, config);
        config.setUpdateBy(userId);
        config.setUpdateTime(new Date());
        updateIgnoreNull(config);

        // 添加历史版本记录
        insertTemplateHistory(userId, data);
    }

    @Override
    public SqfwTemplateConfig getDetail(String id) {
        return fetch(id);
    }

    @Override
    public Map<String, String> uploadTemplateFile(TempFile file, String templateConfigId) {
        Map<String, String> resultMap = Maps.newHashMap();

        // wzy 2024-01-16 上传的原始模板也需要进行保存
        String originalResultUrl = sysOssService.upload(file).getFileName();
        if (!originalResultUrl.startsWith("/")) originalResultUrl = "/" + originalResultUrl;
        resultMap.put("originalFileUrl", originalResultUrl);

        if (file == null) Asserts.fail("上传文件不能为空");

        String templateFileUrl = "";

        String submittedFileName = file.getSubmittedFileName();
        String fileSuffix = "";
        String fileName = "";
        try {
            int symbolIndex = submittedFileName.lastIndexOf(".");
            fileSuffix = submittedFileName.substring(symbolIndex + 1);
            fileName = submittedFileName.substring(0, symbolIndex);
        } catch (Exception e) {
            e.printStackTrace();
            Asserts.fail("解析文件类型错误");
        }

        SqfwTemplateConfig templateConfig = fetch(templateConfigId);
        if (templateConfig == null) Asserts.fail("配置数据不存在");

        Set<String> supportFileType = Sets.newHashSet();
        supportFileType.add("docx");
        supportFileType.add("xlsx");
        if (!supportFileType.contains(fileSuffix)) Asserts.fail("不支持文件类型");

        if (fileSuffix.equals("docx")) {
            templateFileUrl = transformTemplateDocx(file, templateConfig, fileName);
        }

        // 如果是excel
        if (fileSuffix.equals("xlsx")) {
            templateFileUrl = transformTemplateXlsx(file, templateConfig, fileName);
        }
        resultMap.put("templateFileUrl", templateFileUrl);

        return resultMap;
    }

    /**
     * 将产品上传的word模板转为开发需要的word模板
     *
     * @param file           文件
     * @param templateConfig 模板配置文件
     * @param fileName       文件名称
     * @return 结果
     */
    private String transformTemplateDocx(TempFile file, SqfwTemplateConfig templateConfig, String fileName) {
        String wordUrl = "";

        ByteArrayOutputStream wordOutPutStream = new ByteArrayOutputStream();

        // 从配置中将存储字段封装一下
        Map<String, String> pdfFieldMap = Maps.newHashMap();
        pdfFieldMap.put("网格员签名", "{{cuNoSig}}{{?cuSigs}}{{@cuSig}}{{/cuSigs}}");
        pdfFieldMap.put("填表日期", "{{fillDateStr}}");
        pdfFieldMap.put("pdf前缀", "{{unitName}}");

        String configJsonStr = templateConfig.getConfigJson();
        List<JSONObject> jsonArray = JSONArray.parseArray(configJsonStr, JSONObject.class);
        for (JSONObject jsonObject : jsonArray) {
            String dictName = jsonObject.getString("visDictName");
            String dictCode = jsonObject.getString("dictCode");
            String javaType = jsonObject.getString("javaType");
            if (StringUtils.isBlank(javaType)) continue;

            // 如果是图片
            if (javaType.equals("SqfwImage")) {
                pdfFieldMap.put(dictName, StrFormatter.format("{{?{}}}{{@{}}}{{/{}}}", dictCode + "s", dictCode, dictCode + "s"));
            } else {
                dictCode = StrFormatter.format("{{{}}}", dictCode);
                pdfFieldMap.put(dictName, dictCode);
            }
        }

        // 如果是word文档 需要将产品上传的word文件生成一个我们可用的模板存储起来
        try {
            // 凭证 不然切换后有水印
            InputStream is = new ClassPathResource("/license.xml").getInputStream();
            License aposeLic = new License();
            aposeLic.setLicense(is);
            Document document = new Document(file.getInputStream());
            for (String fieldCName : pdfFieldMap.keySet()) {
                String code = pdfFieldMap.get(fieldCName);

                fieldCName = "{{" + fieldCName + "}}";
                document.getRange().replace(fieldCName, code, false, false);
            }
            document.save(wordOutPutStream, SaveFormat.DOCX);

            // 上传pdf
            System.out.println("开始上传模板转换文件");
            String templateWordFileName = "temp.pdf";
            if (StringUtils.isNotBlank(fileName)) {
                templateWordFileName = fileName + ".docx";
            }
            SysOss pdfSysOss = sysOssService.upload(wordOutPutStream.toByteArray(), templateWordFileName);
            wordUrl = pdfSysOss.getFileName();
            if (!wordUrl.startsWith("/")) {
                wordUrl = "/" + wordUrl;
            }
        } catch (Exception e) {
            e.printStackTrace();
            Asserts.fail("");
        } finally {
            IoUtil.close(wordOutPutStream);
        }

        return wordUrl;
    }

    private String transformTemplateXlsx(TempFile file, SqfwTemplateConfig templateConfig, String fileName) {
        String resultUrl = "";

        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("填报单位", "{unitName}");
        paramMap.put("下载时间", "{downloadDateStr}");

        String configJsonStr = templateConfig.getConfigJson();
        List<JSONObject> jsonArray = JSONArray.parseArray(configJsonStr, JSONObject.class);
        List<Map<String, Object>> dataList = Lists.newArrayList();

        Map<String, Object> rowMap = Maps.newHashMap();
        rowMap.put("序号", "{data.num}");
        rowMap.put("填表时间", "{data.fillDateStr}");
        for (JSONObject jsonObject : jsonArray) {
            String dictName = jsonObject.getString("visDictName");
            String dictCode = jsonObject.getString("dictCode");

            String replaceValue = "{data." + dictCode + "}";
            rowMap.put(dictName, replaceValue);
        }
        dataList.add(rowMap);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            ExcelWriterBuilder builder = EasyExcel.write(outputStream);
            ExcelWriter excelWriter = builder
                    .autoCloseStream(false)
                    .registerWriteHandler(new CustomImageModifyHandler(55))
                    .withTemplate(file.getInputStream())
                    .excelType(ExcelTypeEnum.XLSX).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();

            excelWriter.fill(paramMap, writeSheet);
            excelWriter.fill(new FillWrapper("data", dataList), writeSheet);
            excelWriter.finish();

            IoUtil.close(outputStream);

            fileName = fileName + ".xlsx";
            resultUrl = sysOssService.upload(outputStream.toByteArray(), fileName).getFileName();
            if (!resultUrl.startsWith("/")) {
                resultUrl = "/" + resultUrl;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IoUtil.close(outputStream);
        }

        return resultUrl;
    }

    /**
     * 添加版本管理历史记录
     *
     * @param userId 用户id
     * @param data   数据
     */
    private void insertTemplateHistory(String userId, SqfwTemplateDictConfigUpdateDTO data) {
        String bindingStatus = data.getBindingStatus();
        if (!bindingStatus.equals(DictEnums.VIS_DICT_NOT_BINDING.getCode())) {
            if (StringUtils.isNotBlank(data.getJsonOperationStatus())) {
                // 如果已经开始了绑定字段，并且更改了json就需要将进入历史表中
                SqfwTemplateHistory history = new SqfwTemplateHistory();
                history.setHistoryType(data.getJsonOperationStatus());
                history.setRelatedId(data.getId());
                history.setCreateBy(userId);
                history.setUpdateBy(userId);
                history.setCreateTime(new Date());
                history.setUpdateTime(new Date());
                history.setDataJson(data.getConfigJson());
                sqfwTemplateHistoryService.insert(history);
            }
        }
    }
}
